#pragma once

#include <iostream>
#include <string>
#include <memory>
#include <mutex>
#include <list>
#include <vector>
#include<algorithm>

using namespace std;

#define     OBJSERVERMODE_TEST          0

/**
 *      观察者模式 (智能指针选择: 不需要共享所有权时应该使用unique_ptr而不是shared_ptr)
*/

class Observer;

//抽象被观察者
class Subject {
public:
    Subject() : m_nState(0) {}

    virtual ~Subject() = default;

    virtual void Attach(const std::shared_ptr<Observer> pObserver) = 0;

    virtual void Detach(const std::shared_ptr<Observer> pObserver) = 0;

    virtual void Notify() = 0;

    virtual int GetState() { return m_nState; }

    void SetState(int state) {
        std::cout << "Subject updated !" << std::endl;
        m_nState = state;
    }

protected:
    std::list<std::shared_ptr<Observer>> m_pObserver_list;
    int m_nState;
};

//抽象观察者
class Observer {
public:
    virtual ~Observer() = default;

    Observer(const std::shared_ptr<Subject> pSubject, const std::string &name = "unknown")
        : m_pSubject(pSubject), m_strName(name) {}

    virtual void Update() = 0;

    virtual const std::string &name() { return m_strName; }

protected:
    std::shared_ptr<Subject> m_pSubject;
    std::string m_strName;
};

//具体被观察者
class ConcreteSubject : public Subject {
public:
    void Attach(const std::shared_ptr<Observer> pObserver) override {
        auto iter = std::find(m_pObserver_list.begin(), m_pObserver_list.end(), pObserver);
        if (iter == m_pObserver_list.end()) {
            std::cout << "Attach observer" << pObserver->name() << std::endl;
            m_pObserver_list.emplace_back(pObserver);
        }

    }

    void Detach(const std::shared_ptr<Observer> pObserver) override {
        std::cout << "Detach observer" << pObserver->name() << std::endl;
        m_pObserver_list.remove(pObserver);
    }

    //循环通知所有观察者
    void Notify() override {
        auto it = m_pObserver_list.begin();
        while (it != m_pObserver_list.end()) {
            (*it++)->Update();
        }
    }
};


//具体观察者1
class Observer1 : public Observer {
public:
    Observer1(const std::shared_ptr<Subject> pSubject, const std::string &name = "unknown")
        : Observer(pSubject, name) {}

    void Update() override {
        std::cout << "Observer1_" << m_strName << " get the update.New state is: "
                  << m_pSubject->GetState() << std::endl;
    }
};

//具体观察者2
class Observer2 : public Observer {
public:
    Observer2(const std::shared_ptr<Subject> pSubject, const std::string &name = "unknown")
        : Observer(pSubject, name) {}

    void Update() override {
        std::cout << "Observer2_" << m_strName << " get the update.New state is: "
                  << m_pSubject->GetState() << std::endl;
    }
};


#if 1

class ObjserverSub;

// 被观察者基类
class ObservedSub
{
public:
    ObservedSub(){}
    virtual ~ObservedSub()
    {
        std::cout << __PRETTY_FUNCTION__ <<" | this: " << this <<endl;
    };

    virtual void attach(std::unique_ptr<ObjserverSub> &ptr) = 0;
    virtual void detach(std::unique_ptr<ObjserverSub> &ptr) = 0;
    virtual void notify() = 0;

    virtual int state()
    {
        return m_state;
    }

    void setState(int state)
    {
        m_state = state;
    }

protected:
    std::list<std::unique_ptr<ObjserverSub>> m_pObjserverList;          // 观察者容器, 存放观察者
    int m_state = false;
};

// 观察者基类
class ObjserverSub
{
public:
    ObjserverSub(unique_ptr<ObservedSub> &ptr, const string &name)
    {
        std::cout << "ptr.get: " << ptr.get() <<" |name: " << name << endl;
        m_ObservedSubPtr.reset(ptr.release());
        m_name = name;
    }

    virtual ~ObjserverSub()
    {
        std::cout << __PRETTY_FUNCTION__ <<endl;
    };

    virtual void update() = 0;

    virtual string name()
    {
        return m_name;
    }

protected:
    string m_name = string();
    unique_ptr<ObservedSub> m_ObservedSubPtr;
};

// 观察者派生类1
class ObjserverSub1: public ObjserverSub
{
public:
    ObjserverSub1(unique_ptr<ObservedSub> &ptr, const string &name) : ObjserverSub(ptr, name)
    {

    }
    ~ObjserverSub1()
    {
        std::cout << __PRETTY_FUNCTION__ <<endl;
    }

    void update() override
    {
        std::cout << "ObjserverSub1" <<  m_name << " get the update.New state is:" << m_ObservedSubPtr->state() << endl;
    }

};


// 观察者派生类2
class ObjserverSub2: public ObjserverSub
{
public:
    ObjserverSub2(unique_ptr<ObservedSub> &ptr, const string &name) : ObjserverSub(ptr, name)
    {

    }
    ~ObjserverSub2()
    {
        std::cout << __PRETTY_FUNCTION__ <<endl;
    }
    
    void update() override
    {
        std::cout << "ObjserverSub2_" <<  m_name << " get the update.New state is:" << m_ObservedSubPtr->state() << endl;
    }
};

// 被观察者派生类
class ConcreteObservedSub : public ObservedSub
{
public:
    ConcreteObservedSub()
    {

    }
    ~ConcreteObservedSub() override
    {
        std::cout << __PRETTY_FUNCTION__ <<endl;
    }

    void attach(std::unique_ptr<ObjserverSub> &ptr) override
    {
        auto iter = std::find(m_pObjserverList.begin(), m_pObjserverList.end(), ptr);
        if ( iter != m_pObjserverList.end() )
        {
            // 插入
            m_pObjserverList.push_back(std::move(ptr));
            std::cout << "attach Objserver - name: " << ptr->name() << endl;
        }
    }

    void detach(std::unique_ptr<ObjserverSub> &ptr) override
    {
        if ( ptr == nullptr )
            return ;
        m_pObjserverList.remove(ptr);
        std::cout << "detach Objserver, size: " << m_pObjserverList.size() << endl;
    }

    void notify() override
    {
        auto iter = m_pObjserverList.begin();
        while ( iter != m_pObjserverList.end() )
        {
            (*iter++)->update();
        }
    }
};

#endif

void testObjServerMode()
{
#if 1
    std::shared_ptr<Subject> pSubject = std::make_shared<ConcreteSubject>();// 创建被观察者

    // 创建观察者
    std::shared_ptr<Observer> pObserver1_1 = std::make_shared<Observer1>(pSubject, "1");
    std::shared_ptr<Observer> pObserver1_2 = std::make_shared<Observer1>(pSubject, "2");
    std::shared_ptr<Observer> pObserver1_3 = std::make_shared<Observer1>(pSubject, "3");

    std::shared_ptr<Observer> pObserver2_4 = std::make_shared<Observer2>(pSubject, "4");
    std::shared_ptr<Observer> pObserver2_5 = std::make_shared<Observer2>(pSubject, "5");
    std::shared_ptr<Observer> pObserver2_6 = std::make_shared<Observer2>(pSubject, "6");

    // 注册观察者
    pSubject->Attach(pObserver1_1);
    pSubject->Attach(pObserver1_2);
    pSubject->Attach(pObserver1_3);
    pSubject->Attach(pObserver2_4);
    pSubject->Attach(pObserver2_5);
    pSubject->Attach(pObserver2_6);

    pSubject->SetState(2);// 改变状态
    pSubject->Notify();

    std::cout << std::string(50, '-') << std::endl;

    // 注销观察者
    pSubject->Detach(pObserver1_1);
    pSubject->Detach(pObserver1_2);

    pSubject->SetState(3);
    pSubject->Notify();

    std::cout << endl;

    pSubject->SetState(88);
    pSubject->Notify();

#endif


#if 0
//  创建被观察者
    unique_ptr<ObservedSub> ObservedPtr = unique_ptr<ConcreteObservedSub>(new ConcreteObservedSub);

//  创建观察者
    unique_ptr<ObjserverSub> ObjserverPtr1 = unique_ptr<ObjserverSub1>(new ObjserverSub1(ObservedPtr, string("ObjserverPtr1")));
    unique_ptr<ObjserverSub> ObjserverPtr2 = unique_ptr<ObjserverSub1>(new ObjserverSub1(ObservedPtr, string("ObjserverPtr2")));

//     二次释放
//    ObservedPtr->attach(ObjserverPtr1);
//    ObservedPtr->attach(ObjserverPtr2);
#endif


}


